<!DOCTYPE html>
<html>
  <head>
    <meta name="screen-orientation" content="portrait" />
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0"
    />
    <title>年会抽奖小程序</title>
    <link rel="stylesheet" type="text/css" href="css/reset.css" />
    <link rel="stylesheet" type="text/css" href="css/luckydraw.css" />
  </head>
  <body>
    <div id="app" class="wall" v-cloak>
      <!-- 标签云 -->
      <canvas :id="canvasId" :class="{mask: showResult}" :width="width" :height="height">
        <ul id="tags">
          <li v-for="item in member" :key="item.phone">
            <a href="#" :style="{color: winners.includes(getKey(item)) ? 'yellow' : 'white'}"> {{item.name}} </a>
          </li>
        </ul>
      </canvas>
      <!-- 在线人数 -->
      <div id="connections" class="connections" v-if="syncPush">
        <span>在线人数：{{connections}}</span>
      </div>
      <!-- 获奖名单 -->
      <div id="result-btn" class="result-btn">
        <a href="./result.html" target="_blank">获奖名单</a>
      </div>
      <!-- 抽奖结果 -->
      <div id="result" class="result" v-show="showResult">
        <span v-for="item in currentWinner" :key="item.phone"> {{item.name}}<br />{{item.phone}} </span>
      </div>
      <!-- 操作栏 -->
      <div id="tools" class="tools">
        <button
          v-for="item in prize"
          :key="item.name"
          class="pure-button"
          :class="{ 'button-error': currentPrize?.name === item.name}"
          :disabled="running"
          @click="handleChoosePrize(item)"
        >
          {{item.name}}({{item.quota}})
        </button>
        <button
          class="pure-button"
          :class="{'button-secondary': !running, 'button-success': running}"
          @click="handleToggle"
        >
          {{running?"停!":"开始"}}
        </button>
        <button class="pure-button button-warning" @click="handelReset">重置</button>
      </div>
    </div>
    <script type="text/javascript" src="js/vue.min.js"></script>
    <script type="text/javascript" src="js/tagcanvas.min.js"></script>
    <script type="text/javascript" src="js/confetti.browser.min.js"></script>
    <script type="text/javascript" src="js/server.js"></script>
    <script type="text/javascript">
      const app = new Vue({
        el: "#app",
        data() {
          return {
            member: [],
            prize: [],
            currentPrize: null,
            showResult: false,
            currentWinner: [],
            winnerList: null,
            running: false,
            socket: null,
            socketName: "ws://" + server.ip + ":" + server.port,
            syncPush: true,
            connections: 0,
            canvasId: "ball",
            speed: [0.04, -0.06], // 左右 上下
            width: document.body.offsetWidth,
            height: document.body.offsetHeight,
          };
        },
        computed: {
          winners() {
            const list = [];
            if (this.winnerList) {
              Object.keys(this.winnerList).forEach((prizeName) => {
                this.winnerList[prizeName].forEach((memberItem) => {
                  list.push(this.getKey(memberItem));
                });
              });
            }
            return list;
          },
        },
        watch: {
          showResult(newVal, oldVal) {
            if (newVal) {
              requestAnimationFrame(this.fireworks);
            }
          },
          winnerList(newVal, oldVal) {
            // console.log("🚀 ~ winnerList:", newVal, oldVal);
            // 保存名单(跨页面传输用)
            localStorage.setItem("winnerList", JSON.stringify(newVal));
            // 重载标签云
            this.$nextTick(() => {
              TagCanvas.Reload(this.canvasId);
            });
          },
        },
        created() {
          this.syncPush
            ? this.createSocket()
            : this.loadScript("js/config.js", () => {
                const winnerListStr = localStorage.getItem("winnerList");
                this.init({
                  member: member.length > 0 ? member : this.member,
                  prize: prize.length > 0 ? prize : this.prize,
                  currentPrize: prize.length > 0 ? prize[0] : this.currentPrize,
                  showResult: this.showResult,
                  currentWinner: this.currentWinner,
                  winnerList: winnerListStr !== null ? JSON.parse(winnerListStr) : this.winnerList,
                  running: this.running,
                });
              });
        },
        mounted() {},
        methods: {
          createSocket() {
            // 创建WebSocket实例，连接到指定的服务器地址
            const socket = new WebSocket(this.socketName);
            this.socket = socket;
            // 当连接成功打开时触发的事件
            socket.onopen = (event) => {
              console.log("WebSocket连接已打开");
              // 这里可以进行一些初始化操作，比如向服务器发送连接成功后的标识等
              this.send("tag", "master");
              // 心跳
              setInterval(() => {
                this.send("ping");
              }, 50000);
            };
            // 当接收到服务器发送的消息时触发的事件
            socket.onmessage = (event) => {
              const message = JSON.parse(event.data);
              console.log("WebSocket收到消息", message.emit);
              switch (message.emit) {
                case "init":
                  this.init(message.data);
                  break;
                case "connections":
                  this.connections = message.data;
                  break;
              }
            };
            // 当连接出现错误时触发的事件
            socket.onerror = (error) => {
              console.log("WebSocket连接出错:", error);
              alert("WebSocket连接出错");
            };
            // 当连接关闭时触发的事件
            socket.onclose = (event) => {
              console.log("WebSocket连接已关闭");
              if (confirm("连接已断开，是否重连？")) {
                location.reload();
              }
            };
          },
          loadScript(url, success, error) {
            const script = document.createElement("script");
            script.src = url;
            script.onload = () => {
              typeof success === "function" && success();
            };
            script.onerror = (event) => {
              console.error("无法加载脚本文件：" + event.target.src);
              typeof success === "function" && error(event);
            };
            document.body.appendChild(script);
          },
          send(emit, data = null) {
            console.log("🚀 ~ send:", { emit, data });
            this.syncPush && this.socket.send(JSON.stringify({ emit, data }));
          },
          getKey(item) {
            return item.name + "-" + item.phone;
          },
          // 初始化
          init({ member, prize, currentPrize, showResult, currentWinner, winnerList, running }) {
            this.member = member;
            this.prize = prize;
            this.currentPrize = currentPrize;
            this.showResult = showResult;
            this.currentWinner = currentWinner;
            this.winnerList = winnerList;
            this.running = running;
            // this.$nextTick中的回调函数就会在 DOM 更新后执行
            this.$nextTick(() => {
              TagCanvas.Start(this.canvasId, "tags", {
                textColour: null,
                textHeight: 14,
                initial: this.speed,
                dragControl: true,
              });
              // 恢复状态
              running === true && this.start(true);
            });
            // 清除历史记录
            if (winnerList === null && localStorage.getItem("winnerList")) {
              localStorage.removeItem("winnerList");
            }
          },
          // 开始抽奖
          start(resume = false) {
            if (resume !== true) {
              if (this.prize.length === 0) {
                alert("奖品列表为空");
                return;
              }
              if (this.winners.length >= this.member.length) {
                alert("可中奖人数不足");
                return;
              }
              if (this.winnerList && this.winnerList[this.currentPrize.name]) {
                if (!confirm("当前奖项已有中奖名单，是否重抽?")) {
                  return;
                }
              }
              this.running = true;
              this.currentWinner = [];
              this.showResult = false;
            }
            TagCanvas.SetSpeed(
              this.canvasId,
              this.speed.map((item) => item * 100)
            );
            if (resume !== true) {
              this.send("start", {
                running: this.running,
                currentWinner: this.currentWinner,
                showResult: this.showResult,
              });
            }
          },
          // 停止抽奖
          stop() {
            const currentWinner = this.lottery(this.currentPrize.quota);
            TagCanvas.SetSpeed(this.canvasId, this.speed);
            this.running = false;
            this.currentWinner = currentWinner;
            this.showResult = true;
            if (this.winnerList === null) {
              this.winnerList = { [this.currentPrize.name]: currentWinner };
            } else {
              if (this.winnerList[this.currentPrize.name]) {
                this.$delete(this.winnerList, this.currentPrize.name);
              }
              this.$set(this.winnerList, this.currentPrize.name, currentWinner);
            }
            this.send("stop", {
              running: this.running,
              currentWinner: this.currentWinner,
              showResult: this.showResult,
              winnerList: this.winnerList,
            });
          },
          lottery(count) {
            return this.member
              .filter((item) => {
                return !this.winners.includes(this.getKey(item));
              })
              .map((item) => {
                item.score = Math.random();
                return item;
              })
              .sort((a, b) => {
                return a.score - b.score;
              })
              .slice(0, count)
              .map((item) => {
                delete item.score;
                return item;
              });
          },
          fireworks() {
            function fire(particleRatio, opts) {
              confetti({
                ...{
                  origin: { y: 0.7 },
                },
                ...opts,
                particleCount: Math.floor(200 * particleRatio),
              });
            }
            fire(0.25, {
              spread: 26,
              startVelocity: 55,
            });
            fire(0.2, {
              spread: 60,
            });
            fire(0.35, {
              spread: 100,
              decay: 0.91,
              scalar: 0.8,
            });
            fire(0.1, {
              spread: 120,
              startVelocity: 25,
              decay: 0.92,
              scalar: 1.2,
            });
            fire(0.1, {
              spread: 120,
              startVelocity: 45,
            });
          },
          handleChoosePrize(prize) {
            this.currentPrize = prize;
            this.showResult = false;
            this.send("choosePrize", {
              currentPrize: this.currentPrize,
              showResult: this.showResult,
            });
          },
          handleToggle() {
            this.running ? this.stop() : this.start();
          },
          handelReset() {
            if (confirm("确定要重置么？所有之前的抽奖历史将被清除！")) {
              this.send("reset");
              localStorage.clear();
              location.reload();
            }
          },
        },
      });
    </script>
  </body>
</html>
